/**
 * Copyright 2017 orivil Authors. All rights reserved.
 * Use of this source code is governed by a MIT-style
 * license that can be found at https://mit-license.org.
 */

package trace

import (
	"runtime"
	"strconv"
	"bytes"
)

type container struct {
	err error
	traces [][]byte
}

func (c *container) String() string {
	buf := bytes.NewBuffer(nil)
	buf.WriteString(c.err.Error())
	for _, file := range c.traces {
		buf.Write(file)
	}
	return buf.String()
}

func (c *container) Error() string {
	return c.String()
}

// 忽略 trace, 只能忽略未被重新包装的 error
func IgnoreTrace(err error) error {
	if c, ok := err.(*container); ok {
		return c.err
	} else {
		return err
	}
}

func Error(err error) error {
	if err != nil {
		return DeepError(err, 2, 1)
	}
	return nil
}

func DeepError(err error, startTrace, traceDeep int) error {
	if err != nil {
		if traceDeep < 1 {
			traceDeep = 1
		}
		if startTrace < 1 {
			startTrace = 1
		}
		var c *container
		if ct, ok := err.(*container); ok {
			c = ct
		} else {
			c = &container{err:err}
		}
		for i := startTrace; i < startTrace + traceDeep; i++ {
			if _, file, line, ok := runtime.Caller(i); ok {
				c.traces = append(c.traces, []byte("\n" + file + ":" + strconv.Itoa(line)))
			}
		}
		return c
	}
	return nil
}